package com.ygp.dtp.core.monitor.collector.abstracts.strategy;

import com.ygp.dtp.common.dto.ThreadPoolState;
import com.ygp.dtp.common.enums.CollectorTypeEnum;
import com.ygp.dtp.core.monitor.collector.abstracts.AbstractCollector;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @description: 度量收集器
 * @motto: 代码源于生活，高于生活艺术
 * @author: zhouhengzhe
 * @date: 2022/8/9 10:08
 * @since 1.0
 **/
@Slf4j
public class MicroMeterCollector extends AbstractCollector {

    /**
     * 度量缓存
     */
    private static final Map<String, ThreadPoolState> GAUGE_CACHE = new ConcurrentHashMap<>();

    public static final String DTP_METRIC_NAME_PREFIX = "thread.pool";

    public static final String TAG_KEY = DTP_METRIC_NAME_PREFIX + ".name";

    /**
     * 收集关键指标。
     *
     * @param threadPoolState 线程池相关状态参数
     */
    @Override
    public void collect(ThreadPoolState threadPoolState) {
        ThreadPoolState oldState = GAUGE_CACHE.get(threadPoolState.getDtpName());
        if (Objects.isNull(oldState)) {
            GAUGE_CACHE.put(threadPoolState.getDtpName(), threadPoolState);
        } else {
            BeanUtils.copyProperties(threadPoolState, oldState);
        }
        gauge(GAUGE_CACHE.get(threadPoolState.getDtpName()));
    }

    /**
     * 收集类型
     *
     * @return 收集类型
     */
    @Override
    public String type() {
        return CollectorTypeEnum.MICROMETER.name();
    }

    /**
     * 度量收集
     *
     * @param threadPoolState 线程池状态
     */
    private void gauge(ThreadPoolState threadPoolState) {
        List<Tag> tags = Collections.singletonList(Tag.of(TAG_KEY, threadPoolState.getDtpName()));
        Metrics.gauge(metricsName("core.size"), tags, threadPoolState, ThreadPoolState::getCorePoolSize);
        Metrics.gauge(metricsName("maximum.size"), tags, threadPoolState, ThreadPoolState::getMaxPoolSize);
        Metrics.gauge(metricsName("current.size"), tags, threadPoolState, ThreadPoolState::getPoolSize);
        Metrics.gauge(metricsName("largest.size"), tags, threadPoolState, ThreadPoolState::getLargestPoolSize);
        Metrics.gauge(metricsName("active.count"), tags, threadPoolState, ThreadPoolState::getActiveCount);

        Metrics.gauge(metricsName("task.count"), tags, threadPoolState, ThreadPoolState::getTaskCount);
        Metrics.gauge(metricsName("completed.task.count"), tags, threadPoolState, ThreadPoolState::getCompletedTaskCount);
        Metrics.gauge(metricsName("wait.task.count"), tags, threadPoolState, ThreadPoolState::getWaitTaskCount);

        Metrics.gauge(metricsName("queue.size"), tags, threadPoolState, ThreadPoolState::getQueueSize);
        Metrics.gauge(metricsName("queue.capacity"), tags, threadPoolState, ThreadPoolState::getQueueCapacity);
        Metrics.gauge(metricsName("queue.remaining.capacity"), tags, threadPoolState, ThreadPoolState::getQueueRemainingCapacity);

        Metrics.gauge(metricsName("reject.count"), tags, threadPoolState, ThreadPoolState::getRejectCount);
    }

    private String metricsName(String name) {
        return String.join(",", DTP_METRIC_NAME_PREFIX, name);
    }

}
